﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Text;
using System.Linq;
using System.Windows.Forms;

namespace imperialismIIEditor
{
    public partial class Form1 : Form
    {
        private readonly OpenFileDialog chooseOpenFileDialog = new OpenFileDialog();  //文件对话框
        private string chosenFile;            //当前文件路径                                 
        private FileStream _fileStream;

        private List<PartModel> _curParts = new List<PartModel>();
        private long _curPosition = 0;

        public Form1()
        {
            InitializeComponent();

            
        }

        private void Open_Click(object sender, EventArgs e)
        {
            _curPosition = 0;
            listBox1.Items.Clear();
            _curParts.Clear();

            chooseOpenFileDialog.ShowDialog();
            chosenFile = chooseOpenFileDialog.FileName;
            Text = Path.GetFileName(chosenFile);//从其获取文件名和扩展名的路径字符串。 
        }

        private void OnOpenFileDialogOK(object Sender, CancelEventArgs e)
        {
            if (string.IsNullOrEmpty(chosenFile))
                return;
            _fileStream = new FileStream(chosenFile, FileMode.Open, FileAccess.ReadWrite);
        }

        //读取选中的文件并显示；
        private void DisplayFile()
        {
            int nCols = 16;
            FileStream inStream = new FileStream(chosenFile, FileMode.Open, FileAccess.ReadWrite);//实例化FileStream
            long nBytesToRead = inStream.Length;  //确定文件有多少个字节；
            //if (nBytesToRead > 65536 / 4)   
            //    nBytesToRead = 65536 / 4;
            int nLines = (int)(nBytesToRead / nCols);//计算总共显示多少行；
            string[] lines = new string[nLines];
            int nBytesRead = 0;//读取的字节数
            for (int i = 0; i < nLines; i++)
            {
                StringBuilder nextLine = new StringBuilder();//构造每一文本行
                //nextLine.Capacity = 4 * nCols;
                for (int j = 0; j < nCols; j++)
                {
                    int nextByte = inStream.ReadByte();
                    nBytesRead++;
                    //if (nextByte < 0 || nBytesRead > 65536)
                    //    break;
                    char nextChar = (char)nextByte;//强制转换为字符

                    if (nextChar < 16)  //值小于16的字符的显示方法
                        nextLine.Append(" 0" + string.Format("{0,1:X}", (int)nextChar));
                    //else if
                    //    (char.IsLetterOrDigit(nextChar) || char.IsPunctuation(nextChar))
                    //    nextLine.Append("  " + nextChar + "  ");
                    else
                        nextLine.Append(" " + string.Format("{0,2:X}", (int)nextChar));

                }
                lines[i] = nextLine.ToString();
            }
            inStream.Close();
        }

        private void btnLookDown_Click(object sender, EventArgs e)
        {
            OnOpenFileDialogOK(null, null);
            listBox1.Items.Clear();
            listBox1.SelectedIndexChanged -= listBox1_SelectedIndexChanged;
            _fileStream.Position = _curPosition  = 0;
            _curParts.Clear();
            //国家代码
            var country = cmbCountry.SelectedItem.ToString().Substring(0, 2);

            long size = _fileStream.Length;//当前位置到文件末尾的距离

            int part = 0; int city = 0; int capital = 0;
            _fileStream.Position = 20000;
            for (long i = 20000; i < size; i++)
            {
                //直接读四十个字节
                var buffer = new byte[40];
                var count = _fileStream.Read(buffer, 0, 40);
                _fileStream.Position -= 39;
                if (count < 40) break;
                //直接判断啊
                if (!CheckByte(buffer[4], country)) continue;
                if (!CheckByte(buffer[5], country)) continue;
                if (!CheckByte(buffer[7], "00")) continue;
                if (!CheckByte(buffer[8], "00")) continue;
                if (!CheckByte(buffer[9], "00")) continue;
                if (!CheckByte(buffer[25], "FF")) continue;
                if (!CheckByte(buffer[26], "FF")) continue;
                if (!CheckByte(buffer[27], "FF")) continue;
                if (!CheckByte(buffer[28], "FF")) continue;
                var tp = buffer[29] < 16 ?
                        "0" + string.Format("{0,1:X}", buffer[29]) :
                        string.Format("{0,2:X}", buffer[29]);
                if (tp == "00") part++;
                else if (tp == "2A") city++;
                else if (tp == "37") capital++;
                else if (tp == "22") city++;
                else continue;

                var _curPart = buffer;
                var builder = new StringBuilder();
                var rt = 0;
                builder.Append(_fileStream.Position - 1 + " ");
                foreach (var c in _curPart)
                {
                    if (16 > c)
                        builder.Append(" 0" + string.Format("{0,1:X}", c));
                    else
                        builder.Append(" " + string.Format("{0,2:X}", c));
                    rt++;
                }
                _curPosition = _fileStream.Position;
                listBox1.Items.Add(builder.ToString());
                _curParts.Add(PartModel.GetModel(_curPart, _fileStream.Position - 1));
                #region
                //int nextByte = _fileStream.ReadByte();
                //var firstchar = (char)nextByte;
                //var first = firstchar < 16 ? 
                //    "0" + string.Format("{0,1:X}", (int)firstchar) :
                //    string.Format("{0,2:X}", (int)firstchar);
                //if (country.Equals(first))
                //{//找到第一个匹配的，继续找
                //    nextByte = _fileStream.ReadByte();
                //    var scdchar = (char)nextByte;
                //    var scd = scdchar < 16 ?
                //        "0" + string.Format("{0,1:X}", (int)scdchar) :
                //        string.Format("{0,2:X}", (int)scdchar);
                //    if (country.Equals(scd))
                //    {//找到第二个，第三个，返回去找第一个字节是00
                //        _fileStream.Position -= 6;
                //        nextByte = _fileStream.ReadByte();
                //        _fileStream.Position += 6;
                //        var trdchar = (char)nextByte;
                //        var trd = trdchar < 16 ?
                //        "0" + string.Format("{0,1:X}", (int)trdchar) :
                //        string.Format("{0,2:X}", (int)trdchar);
                //        if(true) //(trd.Equals("00"))
                //        {//三个都对了，读当前字节后面的第19，20，21，22字节
                //            var ffff = new byte[5];
                //            _fileStream.Position += 18;
                //            var fsize = _fileStream.Read(ffff,0,5);
                //            _curPosition = _fileStream.Position; ;
                //            if (fsize < 5) continue;
                //            var isfind = true;
                //            for (int j = 0; j < 5;j++ )
                //            {
                //                if (isfind && j == 4 && ffff[j] == 0)
                //                    part += 1;
                //                if (j == 4 && string.Format("{0,2:X}",(int)ffff[j]) == "2A")
                //                    city += 1;
                //                if (j == 4 && string.Format("{0,2:X}", (int)ffff[j]) == "37")
                //                    capital += 1;
                //                if (j != 4 && string.Format("{0,2:X}", (int)ffff[j]) != "FF")
                //                    isfind = false;
                //            }
                //            if (isfind)
                //            {//找到了，回到起点，读取40个字节
                //                _fileStream.Position = i -4;
                //                var _curPart =new byte[40];
                //                var csize = _fileStream.Read(_curPart, 0, 40);
                //                _curPosition = _fileStream.Position; ;
                //                if (csize < 40)
                //                    continue;
                //                var builder = new StringBuilder();
                //                var rt = 0;
                //                builder.Append(_fileStream.Position-40 + " ");
                //                foreach (var c in _curPart)
                //                {
                //                    if (16 > c)
                //                        builder.Append(" 0" + string.Format("{0,1:X}", c));
                //                    else
                //                        builder.Append(" " + string.Format("{0,2:X}", c));
                //                    rt++;
                //                }
                //                _curPosition = _fileStream.Position;
                //                listBox1.Items.Add(builder.ToString());
                //                _curParts.Add(PartModel.GetModel(_curPart,_fileStream.Position -40));
                //            }
                //        }
                //    }
                //}
                #endregion
            }
            lbPart.Text = string.Format("产地:{0}", part);
            lbCity.Text = string.Format("城市:{0}", city);
            lbCapital.Text = string.Format("首都:{0}", capital);
            listBox1.SelectedIndexChanged += listBox1_SelectedIndexChanged;
            MessageBox.Show("读取完成");
            _fileStream.Close();
            _curParts = _curParts.OrderBy(pt => pt.StartPosition).ToList();
            DrwaMap();
        }

        private void cmbProduct_SelectedIndexChanged(object sender, EventArgs e)
        {
            //产品代码
            var product = cmbProduct.SelectedItem.ToString().Substring(0, 2);
            //从产品代码决定地形和产地
            switch (product)
            {
                case "00"://羊毛
                    SetArea("02");//丘陵，羊
                    SetProductArea("07");//羊场
                    break;
                case "0C"://木材
                case "01"://原木
                    SetArea("01");
                    SetProductArea("0D");
                    break;
                case "02"://锡
                    SetArea("02");
                    SetProductArea("08");
                    break;
                case "03"://铜
                    SetArea("02");
                    SetProductArea("08");
                    break;
                case "04"://铁
                    SetArea("02");
                    SetProductArea("08");
                    break;
                case "05"://煤
                    SetArea("02");
                    SetProductArea("08");
                    break;
                case "06"://棉花
                    SetArea("07");
                    SetProductArea("02");
                    break;
                case "07"://糖
                    SetArea("07");
                    SetProductArea("10");
                    break;
                case "08"://烟草
                    SetArea("07");
                    SetProductArea("11");
                    break;
                case "09"://毛皮
                    SetArea("06");
                    SetProductArea("12");
                    break;
                case "0A"://马
                    SetArea("00");
                    SetProductArea("04");
                    break;
                case "0B"://布
                case "0D"://纸
                case "0E"://青铜  
                case "0F"://铁
                case "10"://港
                case "11"://糖
                case "12"://雪茄
                case "13"://皮帽
                case "15": //鱼
                    SetArea("00");
                    SetProductArea("00");
                    break;
                case "14"://谷物
                    SetArea("07");
                    SetProductArea("05");
                    break;
                case "16"://牛
                    SetArea("00");
                    SetProductArea("03");
                    break;
                case "17"://香料
                    SetArea("07");
                    SetProductArea("06");
                    break;
                case "18"://银
                    SetArea("03");
                    SetProductArea("09");
                    break;
                case "19"://金
                    SetArea("03");
                    SetProductArea("09");
                    break;
                case "1A"://宝石
                    SetArea("03");
                    SetProductArea("09");
                    break;
                case "1B"://钻石
                    SetArea("00");
                    SetProductArea("0B");
                    break;
                case "FF":
                    SetArea("00");
                    SetProductArea("00");
                    break;
                default:
                    break;

            }
        }

        private void SetArea(string area)
        {
            var list = cmbArea.Items.Cast<string>();
            var find = list.FirstOrDefault(cm => cm.Substring(0,2) == area);
            if (find != null)
                cmbArea.SelectedItem = find;
        }

        private void SetProductArea(string area)
        {
            var list = cmbProductArea.Items.Cast<string>();
            var find = list.FirstOrDefault(cm => cm.Substring(0, 2) == area);
            if (find != null)
                cmbProductArea.SelectedItem = find;
        }

        private void SetProduct(string product)
        {
            var list = cmbProduct.Items.Cast<string>();
            var find = list.FirstOrDefault(cm => cm.Substring(0, 2) == product);
            if (find != null)
                cmbProduct.SelectedItem = find;
        }

        private void SetLevel(string level)
        {
            var list = cmbLevel.Items.Cast<string>();
            var find = list.FirstOrDefault(cm => cm.Substring(0, 2) == level);
            if (find != null)
                cmbLevel.SelectedItem = find;
        }

        private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            var line = listBox1.SelectedItem.ToString();
            var charstring = line.Substring(line.IndexOf(" ") + 1, line.Length - line.IndexOf(" ") - 1).Trim();
            var chars = charstring.Split(' ');
            cmbProduct.SelectedIndexChanged -=cmbProduct_SelectedIndexChanged;
            SetArea(chars[1]);
            SetLevel(chars[16]);
            SetProduct(chars[21]);
            SetProductArea(chars[22]);
            cmbProduct.SelectedIndexChanged += cmbProduct_SelectedIndexChanged;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            _fileStream = new FileStream(chosenFile, FileMode.Open, FileAccess.ReadWrite);
            int nums = (int)numNum.Value -1;
                            var list = new List<PartModel>();
            if (nums > 1)
            {
                var start = listBox1.SelectedItem.ToString().Substring(0, listBox1.SelectedItem.ToString().IndexOf(" "));
                var model = _curParts.First(pt => pt.StartPosition.ToString() == start);
                var index = _curParts.IndexOf(model, 0);
                list.Add(model);

                for (int i = index + 1; i < nums + index + 1; i++)
                {
                    list.Add(_curParts[i]);
                }
            }
            else
            {
                list = _curParts.Where(p=>p.isSelected).ToList();
            }
            list.ForEach(mo =>
            {
                //if (mo.PartType == Color.Yellow)
                //{
                    var product = cmbProduct.SelectedItem.ToString().Substring(0, 2);
                    var area = cmbArea.SelectedItem.ToString().Substring(0, 2);
                    var proarea = cmbProductArea.SelectedItem.ToString().Substring(0, 2);
                    var level = cmbLevel.SelectedItem.ToString().Substring(1,1);
                    SetOnePart(product, area, proarea,level, mo.StartPosition);
                //}
            });
            _fileStream.Flush();
            _fileStream.Close();
            btnLookDown_Click(null,null);
        }

        private void SetOnePart(string product, string area, string proarea,string level,long startPosition)
        {
            if (_fileStream.CanWrite)
            {
                _fileStream.Position = startPosition;
                //地形
                _fileStream.Position += 1;//2
                long areah = Convert.ToInt64(area, 16);
                _fileStream.WriteByte((byte)areah);
                //等级
                _fileStream.Position += 14;//17
                long levelh = Convert.ToInt64(level, 16);
                _fileStream.WriteByte((byte)levelh);
                //产物
                _fileStream.Position += 4;//22
                long proh = Convert.ToInt64(product, 16);
                _fileStream.WriteByte((byte)proh);
                //产地
                _fileStream.Position += 0;//23
                long proareah = Convert.ToInt64(proarea, 16);
                _fileStream.WriteByte((byte)proareah);
            }
        }

        private void DrwaMap()
        {
            gbMap.Controls.Clear();
            DrawMapNew();
            CountResource();
            return;
            long lastPosition = _curParts[0].StartPosition ;
            int level = 0;
            for (int i = 0,j=0; i < _curParts.Count; i++,j++)
            {
                //每行最多25个
                var distance = (_curParts[i].StartPosition - lastPosition) / 40;
                var curX = (i-1)/ 25;//上一个part的位置
                if (distance > (25 - curX))
                {
                    j = 0;
                    level++;
                }
                DrawButtom(_curParts[i].Product, _curParts[i].PartType, j, level,_curParts[i].StartPosition);
                lastPosition = _curParts[i].StartPosition;
            }

        }

        private void DrawMapNew()
        {
            //第一次先预计算，把第一个坐标作为0，0
            MapPart lastpart = null;
            var perlist = new List<MapPart>();
            for (int i = 0; i < _curParts.Count; i++)
            {
                MapPart curpart;
                if (i == 0)
                {
                    curpart = lastpart = new MapPart() { Model = _curParts[i] };
                }
                else
                {
                    curpart = new MapPart() { Model = _curParts[i] };
                    var distance = (int)(curpart.Model.StartPosition - lastpart.Model.StartPosition) / 40;
                    //一般distance大于40的时候，就已经换行了
                    if (distance > 40)
                    {
                        curpart.Y = lastpart.Y + 1;//Y坐标+1
                        //这个时候计算真实的距离是否大于108,来确定下一个点相对这当前点的坐标
                        var xddis = distance + lastpart.X - 108;
                        //这个相对的距离就是换行后相对于上一个点的X坐标
                        curpart.X = xddis;
                    }
                    else
                    {//没有换行
                        curpart.Y = lastpart.Y;
                        curpart.X = lastpart.X + distance;
                    }
                }
                perlist.Add(curpart);
                lastpart = curpart;
            }
            //一次循环后，会得到一个相对于第一个点是0，0的坐标图，
            //这个时候再循环一次，找出X坐标最大的负偏移，作为画地图时第一个点的偏移
            var smallest = perlist.Min(p => p.X);
            //再次循环，起始点的X进行偏移
            perlist.Clear();
            for (int i = 0; i < _curParts.Count; i++)
            {
                MapPart curpart;
                if (i == 0)
                {
                    curpart = lastpart = new MapPart(-smallest,0) { Model = _curParts[i] };
                }
                else
                {
                    curpart = new MapPart() { Model = _curParts[i] };
                    var distance = (int)(curpart.Model.StartPosition - lastpart.Model.StartPosition) / 40;
                    //一般distance大于40的时候，就已经换行了
                    if (distance > 40)
                    {
                        curpart.Y = lastpart.Y + 1;//Y坐标+1
                        //这个时候计算真实的距离是否大于108,来确定下一个点相对这当前点的坐标
                        var xddis = distance + lastpart.X - 108;
                        //这个相对的距离就是换行后相对于上一个点的X坐标
                        curpart.X = xddis;
                    }
                    else
                    {//没有换行
                        curpart.Y = lastpart.Y;
                        curpart.X = lastpart.X + distance;
                    }
                }
                perlist.Add(curpart);
                lastpart = curpart;
            }
            smallest = perlist.Min(p => p.X);

            foreach (var part in perlist)
            {
                DrawButtomNew(part, 30);
            }
        }

        private void DrawButtomNew(MapPart part, int size)
        {
            var btn = new Button();
            btn.Click +=btn_Click;
            var x = part.X * size;
            if (part.Y % 2 == 0) x += size / 2;//偶数航偏移半个位置
            var y = part.Y * size + 20;
            gbMap.Controls.Add(btn);
            btn.SetBounds(x, y, size, size);
            btn.Text = part.Model.Product;
            btn.BackColor = part.Model.PartType;
            btn.Tag = part.Model.StartPosition;

        }

        private void DrawButtom(string text, Color color, int index,int level,long start)
        {
            int size = 20;
            var btn = new Button();
            btn.Click += btn_Click;
            btn.Text = text;
            btn.BackColor = color;
            gbMap.Controls.Add(btn);
            int x = index % 20 * size + 10;
            int y = level * size + 10;
            btn.SetBounds(x, y, size, size);
            btn.Tag = start;
        }

        void btn_Click(object sender, EventArgs e)
        {
            var start = ((Button)sender).Tag.ToString();
            var find = listBox1.Items.Cast<string>().First(item => item.StartsWith(start));
            listBox1.SelectedItem = find;
            var model = _curParts.First(m => m.StartPosition.ToString() == start);
            model.isSelected = !model.isSelected;
            ((Button)sender).BackColor = model.isSelected ? Color.Green : model.PartType;
        }

        private void CountResource()
        {
            foreach (Label item in plLabels.Controls.Cast<Label>().ToList())
            {
                item.Text = item.Text.Substring(0, 2) + ":0,";
            }
            foreach (var model in _curParts)
            {
                switch (model.Product)
                {
                    case "羊毛"://羊毛
                        SetNum("羊毛",4,lbyang);
                        break;
                    case "原木"://原木
                        SetNum("原木", 4, lbmutou);
                        break;
                    case "锡矿"://锡
                        SetNum("锡矿", 4, lbxi);
                        break;
                    case "铜矿"://铜
                        SetNum("铜矿", 4, lbtong);
                        break;
                    case "铁矿"://铁
                        SetNum("铁矿", 4, lbtie);
                        break;
                    case "煤矿"://煤
                        SetNum("煤矿", 4, lbmei);
                        break;
                    case "蔗糖"://糖
                        SetNum("蔗糖", 4, lbtang);
                        break;
                    case "烟草"://烟草
                        SetNum("烟草", 4, lbyancao);
                        break;
                    case "毛皮"://毛皮
                        SetNum("毛皮", 4, lbmaopi);
                        break;
                    case "谷物"://谷物
                        SetNum("谷物", 4, lbguwu);
                        break;
                    case "牛肉"://牛
                        SetNum("牛肉", 4, lbniu);
                        break;
                    case "钻石"://钻石
                        SetNum("钻石", 2000, lbzuanshi);
                        break;
                    case "空地":
                        SetNum("空地", 0, lbkong);
                        break;
                    case "马匹"://马
                        SetNum("马匹", 4, lbma);
                        break;
                    default:
                        break;
                }
            }
        }

        private void SetNum(string name,int count,Label lb)
        {
            var text = lb.Text;
            var num = text.Contains(":") ?
                text.Substring(text.IndexOf(":") + 1, text.IndexOf(",") - text.IndexOf(":")-1) : "0";
            var nm = Convert.ToInt16(num);
            nm++;
            lb.Text = string.Format("{0}:{1},最大:{2}", name, nm, nm * count);
        }

        private bool CheckByte(byte bt, string word)
        {
            var byword = bt < 16 ?
                        "0" + string.Format("{0,1:X}", bt) :
                        string.Format("{0,2:X}", bt);
            return word == byword;
        }
    }

    public class PartModel
    {
        public byte[] Bytes;
        public long StartPosition = 0;
        public Color PartType = Color.GreenYellow;
        public string Product = "无";
        public bool isSelected = false;
        public static PartModel GetModel(byte[] bytes,long position)
        {
            var model = new PartModel();
            model.Bytes = bytes;
            var product = bytes[21] < 16 ?
                        "0" + string.Format("{0,1:X}", bytes[21]) :
                        string.Format("{0,2:X}", bytes[21]);
            var part = Color.Yellow;
            var city = Color.Blue;
            var cap = Color.Red;
            var parttype = bytes[29] < 16 ?
                        "0" + string.Format("{0,1:X}", bytes[29]) :
                        string.Format("{0,2:X}", bytes[29]);
            model.PartType = parttype == "37" ? cap : (parttype == "2A"||parttype == "22") ? city : part;
            model.StartPosition = position;
            switch (product)
            {
                case "00"://羊毛
                    model.Product = "羊毛";
                    break;
                case "01"://原木
                    model.Product = "原木";
                    break;
                case "02"://锡
                    model.Product = "锡矿";
                    break;
                case "03"://铜
                    model.Product = "铜矿";
                    break;
                case "04"://铁
                    model.Product = "铁矿";
                    break;
                case "05"://煤
                    model.Product = "煤矿";
                    break;
                case "06"://棉花
                    model.Product = "棉花";
                    break;
                case "07"://糖
                    model.Product = "蔗糖";
                    break;
                case "08"://烟草
                    model.Product = "烟草";
                    break;
                case "09"://毛皮
                    model.Product = "毛皮";
                    break;
                case "0A"://马
                    model.Product = "马匹";
                    break;
                case "0B"://布
                    model.Product = "丝绸";
                    break;
                case "0C"://木材
                    model.Product = "木材";
                    break;
                case "0D"://纸
                    model.Product = "纸张";
                    break;
                case "0E"://青铜
                    model.Product = "青铜";
                    break;
                case "0F"://铁
                    model.Product = "铁";
                    break;
                case "10"://港
                    model.Product = "钢";
                    break;
                case "11"://糖
                    model.Product = "糖精";
                    break;
                case "12"://雪茄
                    model.Product = "雪茄";
                    break;
                case "13"://皮帽
                    model.Product = "皮帽";
                    break;
                case "15": //鱼
                    model.Product = "鱼";
                    break;
                case "14"://谷物
                    model.Product = "谷物";
                    break;
                case "16"://牛
                    model.Product = "牛肉";
                    break;
                case "17"://香料
                    model.Product = "香料";
                    break;
                case "18"://银
                    model.Product = "银";
                    break;
                case "19"://金
                    model.Product = "金";
                    break;
                case "1A"://宝石
                    model.Product = "宝石";
                    break;
                case "1B"://钻石
                    model.Product = "钻石";
                    break;
                case "FF":
                    model.Product = "空地";
                    break;
                default:
                    break;
            }

            return model;
        }
    }

    public class MapPart
    {
        public int X =0;
        public int Y =0;
        public PartModel Model;
        public MapPart()
        {
        }
        public MapPart(int x, int y)
        {
            X = x;
            Y = y;
        }
    }
}
